﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;

namespace AmiBrokerPlugin
{
    public static partial class Plugin
    {
        // http://195.128.78.52/GAZP.csv?d=d&market=1&em=16842&df=11&mf=2&yf=1980&dt=11&mt=2&yt=2010&p=8&f=GAZP&e=.csv&cn=GAZP&dtf=1&tmf=1&MSOR=0&sep=3&sep2=1&datf=1

        static string url = "http://195.128.78.52/{0}.csv?d=d&market={4}&em={3}&df={1:dd}&mf={1:MM}&yf={1:yyyy}&dt={2:dd}&mt={2:MM}&yt={2:yyyy}&p=8&f={0}&e=.csv&cn={0}&dtf=1&tmf=1&MSOR=0&sep=3&sep2=1&datf=1";

        static IList<Emitent> emitents;
        static IList<Emitent> Emitents
        {
            get
            {
                if (emitents == null)
                {
                    var request = (HttpWebRequest)WebRequest.Create("http://www.finam.ru/scripts/export.js");
                    var text = String.Empty;

                    using (var response = request.GetResponse())
                    using (var stream = response.GetResponseStream())
                    using (var reader = new StreamReader(stream, Encoding.GetEncoding("windows-1251")))
                    {
                        text = reader.ReadToEnd();
                    }

                    var lines = text.Split('\n');
                    var emitentIDs = Regex.Matches(lines[0], "[0-9]+").OfType<Match>().Select(x => Int32.Parse(x.Value)).ToArray();
                    var emitentNames = Regex.Matches(lines[1], "'.*?'").OfType<Match>().Select(x => x.Value.Substring(1, x.Value.Length - 2)).ToArray();
                    var emitentCodes = Regex.Matches(lines[2], "'.*?'").OfType<Match>().Select(x => x.Value.Substring(1, x.Value.Length - 2)).ToArray();
                    var marketIDs = Regex.Matches(lines[3], "[0-9]+").OfType<Match>().Select(x => Int32.Parse(x.Value)).ToArray();

                    emitents = new List<Emitent>();

                    for (int i = 0; i < emitentIDs.Length; i++)
                    {
                        emitents.Add(new Emitent { ID = emitentIDs[i], MarketID = marketIDs[i], Code = emitentCodes[i], Name = emitentNames[i] });
                    }
                }

                return emitents;
            }
        }

        static IList<Market> markets;
        static IList<Market> Markets
        {
            get
            {
                if (markets == null)
                {
                    var request = (HttpWebRequest)WebRequest.Create("http://www.finam.ru/analysis/export/");
                    var text = String.Empty;

                    using (var response = request.GetResponse())
                    using (var stream = response.GetResponseStream())
                    using (var reader = new StreamReader(stream, Encoding.GetEncoding("windows-1251")))
                    {
                        text = reader.ReadToEnd();
                    }
                    var index = text.IndexOf("<select tabindex=\"1\" id=\"market\" name=\"market\"");
                    var marketsText = text.Substring(index, text.IndexOf("</select>", index) - index);
                    markets = Regex.Matches(marketsText, "<option value=\"(.*?)\".*?>(.*?)</option>").OfType<Match>().Select(x => new Market { ID = Int32.Parse(x.Groups[1].Value), Name = x.Groups[2].Value }).ToList();
                }

                return markets;
            }
        }

        static Emitent GetEmitent(string ticker)
        {
            return Emitents.FirstOrDefault(x => x.Code.Equals(ticker, StringComparison.OrdinalIgnoreCase) && x.MarketID == 1) ??
                   Emitents.FirstOrDefault(x => x.Code.Equals(ticker, StringComparison.OrdinalIgnoreCase));
        }

        static void UpdateEmitent(IntPtr ptr)
        {
            var si = (StockInfo)Marshal.PtrToStructure(ptr, typeof(StockInfo));
            var e = GetEmitent(si.ShortName);
            if (e != null)
            {
                var enc = Encoding.GetEncoding("windows-1251");
                var bytes = enc.GetBytes(e.Name);
                for (var i = 0; i < (bytes.Length > 127 ? 127 : bytes.Length); i++)
                {
                    Marshal.WriteByte(new IntPtr(ptr.ToInt32() + 144 + i), bytes[i]);
                }
                Marshal.WriteByte(new IntPtr(ptr.ToInt32() + 144 + bytes.Length), 0x0);

                var marketIndex = Markets.IndexOf(Markets.FirstOrDefault(x => x.ID == e.MarketID));
                Marshal.WriteInt32(new IntPtr(ptr.ToInt32() + 476), marketIndex);
            }
        }

        unsafe static int GetQuotes(string ticker, Periodicity periodicity, int lastValid, int size, Quotation* quotes)
        {
            var emitent = GetEmitent(ticker);

            if (emitent == null)
            {
                return lastValid + 1;
            }

            var lastDate = lastValid < 0 ? DateTime.Today.AddYears(-20) : Plugin.UnpackDate(quotes[lastValid].DateTime);

            var data = Get(String.Format(url, ticker, lastDate, DateTime.Now, emitent.ID, emitent.MarketID));

            if (String.IsNullOrEmpty(data))
            {
                return lastValid + 1;
            }

            var lines = data.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            var linesCount = lines.Length;

            if (lastValid < 0 || linesCount >= size)
            {
                var i = 0;

                for (var j = linesCount > size ? linesCount - size : 0; j < linesCount; j++)
                {
                    UpdateQuote(out quotes[i], lines[j]);
                    i++;
                }

                return i;
            }

            if (lastValid + linesCount <= size)
            {
                var i = lastValid;

                for (var j = 0; j < linesCount; j++)
                {
                    UpdateQuote(out quotes[i], lines[j]);
                    i++;
                }

                return i;
            }

            var shift = lastValid + linesCount - size;

            for (var i = 0; i <= lastValid - shift; i++)
            {
                quotes[i] = quotes[i + shift];
            }

            var k = lastValid - shift;

            for (var j = 0; j < linesCount; j++)
            {
                UpdateQuote(out quotes[k], lines[j]);
                k++;
            }

            return k;
        }

        static void UpdateQuote(out Quotation quote, string data)
        {
            var item = data.Split(';');
            quote.DateTime = PackDate(DateTime.ParseExact(item[2] + item[3], "yyyyMMddHHmmss", Culture));
            quote.Price = Single.Parse(item[7], Culture);
            quote.Open = Single.Parse(item[4], Culture);
            quote.High = Single.Parse(item[5], Culture);
            quote.Low = Single.Parse(item[6], Culture);
            quote.Volume = Single.Parse(item[8], Culture);
            quote.OpenInterest = 0;
            quote.AuxData1 = 0;
            quote.AuxData2 = 0;
        }

        static string Get(string url)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);

            using (var response = request.GetResponse())
            using (var stream = response.GetResponseStream())
            using (var reader = new StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }
    }
}
